package com.yueqian.common;

import com.yueqian.controller.SysLogController;
import com.yueqian.domain.SysLog;
import com.yueqian.service.ISysLogService;
import com.yueqian.service.impl.SysLogServiceImpl;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Component//可以被spring容器管理到的组件类
@Aspect //切面类
public class LogAop {

    private Date startTime; //方法执行开始时间
    private Method executeMethod;  //要执行的方法
    private Class<?> executeClass;
    private String methodName;

    //从容器中获取一个请求对象
    @Autowired
    private HttpServletRequest request;
    ////从容器中获取一个日志服务层对象
    @Autowired
    private ISysLogService sysLogService;


    /*
     //获取切点表达式切到的并且要执行的类的对象和方法的对象
     */
    @Before(value = "execution(* com.yueqian.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        //获取当前时间
        startTime = new Date();
        //从切点对象中获取访问的类
        executeClass = jp.getTarget().getClass();
        //从切点中获取被访问method的名称
        methodName = jp.getSignature().getName();
        //被访问方法的参数
        Object[] args = jp.getArgs();
        if (args == null || args.length == 0) { //表示空参方法
            executeMethod = executeClass.getMethod(methodName);
        }
        //表示有参数
        Class[] argsClass = new Class[args.length];
        //将Object[]数组转换成Class[]数组
        for (int i = 0; i < args.length; i++) {
            Class<?> aClass1 = args[i].getClass();
            argsClass[i] = aClass1;
        }
        executeMethod = executeClass.getMethod(methodName, argsClass);
    }

    @After(value = "execution(* com.yueqian.controller.*.*(..))")
    public void doAfter(JoinPoint jp) throws Exception {
        //类上的注解
        RequestMapping requestMappingClassAnno = null;
        //方法上的注解
        RequestMapping requestMappingMethodAnno = null;
        //方法上RequestMapping注解中的value属性的值
        String[] methodValues = null;
        //类上RequestMapping注解中的value属性的值
        String[] classValues = null;
        //获取要执行的类不是日志管理的控制器类
        if (executeClass != SysLogController.class) {
            //获取要执行类上的RequestMapping注解对象
            requestMappingClassAnno = executeClass.getAnnotation(RequestMapping.class);
            classValues = requestMappingClassAnno.value();
        }
        if (requestMappingClassAnno != null) {
            requestMappingMethodAnno = executeMethod.getAnnotation(RequestMapping.class);
        }
        if (requestMappingMethodAnno != null) {
            methodValues = requestMappingMethodAnno.value();
            //将类上注解的value值与方法上注解的value值进行拼接
            String url = classValues[0] + "--" + methodValues[0];
            //给日志记录对象封装数据
            SysLog sysLog = new SysLog();
            sysLog.setMethod(executeClass.getName() + "." + methodName);
            sysLog.setUrl(url);
            sysLog.setExecutionTime(new Date().getTime() - startTime.getTime());
            sysLog.setIp(request.getRemoteAddr());
            //从springsecurity认证成功的对象中获取用户名
            String loginedUsername = SecurityContextHolder.getContext().getAuthentication().getName();
            sysLog.setUsername(loginedUsername);
            sysLog.setVisitTime(startTime);
            //调用服务层存储该日志对象
            sysLogService.save(sysLog);
        }
    }
}
